/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package elaborate.tag_analysis.client.actions;

import elaborate.tag_analysis.client.actions.closeness_centrality.ClosenessCentralityCalc;
import elaborate.tag_analysis.client.actions.ui.MultipleFileSelectionDialog;
import elaborate.tag_analysis.client.actions.ui.MultipleFileSelectionPanel;
import elaborate.tag_analysis.client.actions.ui.multiplefileselector.MultipleFileSelectionConfEntry;
import elaborate.tag_analysis.client.graph.Graph;
import elaborate.tag_analysis.client.graph.SimpleSparseGraph;
import elaborate.task.Task;
import java.awt.Frame;
import java.awt.event.ActionEvent;
import java.io.*;
import java.util.*;

/**
 *
 * @author lendle
 */
public class CalculateClosenessCentralityActionHandler extends BaseActionHandler {
    @Override
    protected void asyncHandleAction(ActionEvent event) {
        try {
            List<MultipleFileSelectionConfEntry> entries = new ArrayList<MultipleFileSelectionConfEntry>();

            MultipleFileSelectionConfEntry netFileEntry = new MultipleFileSelectionConfEntry();
            netFileEntry.setId("net");
            netFileEntry.setDisplayName("Select Network File Prefix");
            entries.add(netFileEntry);

            MultipleFileSelectionConfEntry outputFileEntry = new MultipleFileSelectionConfEntry();
            outputFileEntry.setId("output");
            outputFileEntry.setDisplayName("Select Output File");
            outputFileEntry.setSave(true);
            entries.add(outputFileEntry);

            final MultipleFileSelectionDialog dlg = new MultipleFileSelectionDialog((Frame) context.getMainFrame(), true);
            dlg.getFileSelector().setMultipleFileSelectionConfEntries(entries);
            dlg.setLocationRelativeTo(context.getMainFrame());
            dlg.setVisible(true);

            if (dlg.isOk()) {
                final MultipleFileSelectionPanel fileSelector = dlg.getFileSelector();
                context.executeTask(new Task() {

                    @Override
                    public Object run() throws Exception {
                        ClosenessCentralityCalc calc = new ClosenessCentralityCalc();
                        File[] files = fileSelector.getSelectedFile("net").getParentFile().listFiles();
                        PrintWriter output = null;
                        try {
                            List<Entry> allValuesList = new ArrayList<Entry>();
                            output = new PrintWriter(new OutputStreamWriter(new FileOutputStream(fileSelector.getSelectedFile("output")), "utf-8"));
                            for (File file : files) {
                                if (file.getAbsolutePath().startsWith(fileSelector.getSelectedFile("net").getAbsolutePath())) {
                                    //load graph information and start calculation
                                    System.out.println("processing: " + file);
                                    Graph g = loadGraphFromNetFile(file);
                                    List points = g.getPoints();
                                    double[] values = calc.calculate(g);
                                    for (int i = 0; i < values.length; i++) {
                                        if (Double.isNaN(values[i])) {
                                            values[i] = 0;
                                        }
                                        allValuesList.add(new Entry((String) points.get(i), values[i]));
                                        
                                    }
                                }
                            }
                            Collections.sort(allValuesList, new Comparator() {

                                @Override
                                public int compare(Object t, Object t1) {
                                    Entry entry0 = (Entry) t;
                                    Entry entry1 = (Entry) t1;
                                    if (entry0.closenessCentrality > entry1.closenessCentrality) {
                                        return -1;
                                    } else if (entry0.closenessCentrality < entry1.closenessCentrality) {
                                        return 1;
                                    } else {
                                        return 0;
                                    }
                                }
                            });
                            for (Entry entry : allValuesList) {
                                output.println("\"" + entry.getTag() + "\" " + entry.getClosenessCentrality());
                            }
                        } finally {
                            if (output != null) {
                                output.close();
                            }
                        }
                        return null;
                    }
                });
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private Graph loadGraphFromNetFile(File file) throws Exception {
        SimpleSparseGraph g = new SimpleSparseGraph();
        g.setDirected(false);
        BufferedReader input = null;
        try {
            input = new BufferedReader(new InputStreamReader(new FileInputStream(file), "utf-8"));
            String str = input.readLine();
            if (str != null) {
                //skip the first line, which is only a vertex number declaration
                str = input.readLine();
                Map<Integer, String> id2TagMap = new HashMap<Integer, String>();
                while (str != null) {
                    if (str.toLowerCase().equals("*edges")) {
                        str = input.readLine();
                        break;
                    }
                    String[] values = str.split("(\\s)+");
                    String tag = values[1].replace("\"", "");
                    id2TagMap.put(Integer.valueOf(values[0]), tag);
                    g.addPoint(tag);
                    str = input.readLine();
                }
                //process the edges part
                while (str != null) {
                    String[] values = str.split("(\\s)+");
                    String src = id2TagMap.get(Integer.valueOf(values[0]));
                    String target = id2TagMap.get(Integer.valueOf(values[1]));
                    g.setConnected(src, target);
                    str = input.readLine();
                }
            }
        } finally {
            if (input != null) {
                input.close();
            }
        }
        return g;
    }

    class Entry{

        private String tag;
        private double closenessCentrality;

        public Entry(String tag, double closenessCentrality) {
            this.tag = tag;
            this.closenessCentrality = closenessCentrality;
        }

        /**
         * Get the value of closenessCentrality
         *
         * @return the value of closenessCentrality
         */
        public double getClosenessCentrality() {
            return closenessCentrality;
        }

        /**
         * Set the value of closenessCentrality
         *
         * @param closenessCentrality new value of closenessCentrality
         */
        public void setClosenessCentrality(double closenessCentrality) {
            this.closenessCentrality = closenessCentrality;
        }

        /**
         * Get the value of tag
         *
         * @return the value of tag
         */
        public String getTag() {
            return tag;
        }

        /**
         * Set the value of tag
         *
         * @param tag new value of tag
         */
        public void setTag(String tag) {
            this.tag = tag;
        }

        @Override
        public boolean equals(Object obj) {
            if (obj == null) {
                return false;
            }
            if (getClass() != obj.getClass()) {
                return false;
            }
            final Entry other = (Entry) obj;
            if (Double.doubleToLongBits(this.closenessCentrality) != Double.doubleToLongBits(other.closenessCentrality)) {
                return false;
            }
            return true;
        }

        @Override
        public int hashCode() {
            int hash = 5;
            hash = 83 * hash + (int) (Double.doubleToLongBits(this.closenessCentrality) ^ (Double.doubleToLongBits(this.closenessCentrality) >>> 32));
            return hash;
        }

        
    }
}
